/*******************************************************************************
 * Copyright (c) 2011 Irineu Martins de Lima Moura (imlm2).
 * This file is part of JBeat.
 * 
 *     JBeat is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     JBeat is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with JBeat.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Irineu Martins de Lima Moura (imlm2) - initial API and implementation
 ******************************************************************************/
package br.ufpe.cin.imlm2.jbeat.soot.throwableset;

import static br.ufpe.cin.imlm2.jbeat.soot.common.CommonExceptions.getARRAYINDEXOUTOFBOUNDS;
import static br.ufpe.cin.imlm2.jbeat.soot.common.CommonExceptions.getNULLPOINTER;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import br.ufpe.cin.imlm2.jbeat.soot.traps.TrapManager;

import soot.Body;
import soot.SootClass;
import soot.jimple.Stmt;
import soot.jimple.StmtSwitch;
import soot.jimple.toolkits.annotation.tags.ArrayCheckTag;
import soot.jimple.toolkits.annotation.tags.NullCheckTag;
import soot.tagkit.Tag;

public abstract class InstructionVisitor implements StmtSwitch {

	protected Set<SootClass> exceptions;
	protected Set<SootClass> cache;
	protected Body body;

	public InstructionVisitor(Body b) {
		super();
		this.body = b;
		this.exceptions = new HashSet<SootClass>();
		this.cache = new HashSet<SootClass>();
	}
	public Set<SootClass> getExceptions(){
		return this.exceptions;
	}

	protected void checkArrayBoundsTag(Stmt stmt) {
		Set<SootClass> throwables = this.cache;
		Tag t = stmt.getTag("ArrayCheckTag");
		if(t != null){
			ArrayCheckTag act = (ArrayCheckTag) t;
			SootClass arrayIOOBException = getARRAYINDEXOUTOFBOUNDS();
			if(act.isCheckLower() || act.isCheckUpper()){
	
				if(!TrapManager.isExceptionCaughtAt(arrayIOOBException, stmt, 
						this.body)) throwables.add(arrayIOOBException);				
			} else {
				if(throwables.contains(arrayIOOBException)) throwables.remove(arrayIOOBException);
			}
		}
	}

	protected void checkNullCheckTag(Stmt stmt) {
		Set<SootClass> throwable = this.cache;
		Tag t = stmt.getTag("NullCheckTag");
		if(t != null){
			NullCheckTag nct = (NullCheckTag) t;
			SootClass nullPointerException = getNULLPOINTER();
			if(nct.needCheck()){			
				if(!TrapManager.isExceptionCaughtAt(nullPointerException, stmt, this.body)) throwable.add(nullPointerException);				
			} else {
				if(throwable.contains(nullPointerException)) throwable.remove(nullPointerException);
			}
		}
	}

	
	protected void filterTrappedOnes(Stmt stmt) {
		Iterator<SootClass> it = this.cache.iterator();
		while(it.hasNext()){
			SootClass next = it.next();
			if(TrapManager.isExceptionCaughtAt(next, stmt, this.body)) it.remove();
		}
	}

}
